﻿namespace EFS.RC.CCC.Presences
{
	/// <summary>
	/// End point presence
	/// </summary>
	internal abstract class EndPoint<EndPointDeployment> : EFS.Common.ISelfDescriptor where EndPointDeployment : EFS.RC.CCC.Deployment.Entities.EndPoint 
	{
		#region Private components
		
		// Sync access
		protected object syncAccess = new object();

		/// Deployment
		private EndPointDeployment endPointDeployment = null;

		/// Application end point
		private EFS.RC.CCC.Application.EndPoints.EndPoint<EndPointDeployment> applicationEndPoint = null;

		#endregion

		/// <summary>
		/// Deployment
		/// </summary>
		/// <param name="endPointDeployment"></param>
		public EndPoint(EndPointDeployment endPointDeployment)
		{
			// check
			EFS.Common.Verify.Reference(endPointDeployment, "endPointDeployment");

			// keep 
			this.endPointDeployment = endPointDeployment;
		}

		/// <summary>
		/// Describe this object into a nice formated string
		/// </summary>
		/// <returns></returns>
		public virtual System.String Describe()
		{
			return System.String.Format("EFS.RC.CCC.Presences.EndPoint {0}", endPointDeployment.URI);
		}

		/// Deployment
		public EndPointDeployment ApplicationEndPointDeployment
		{
			get { return endPointDeployment; }
		}

		/// Application
		public EFS.RC.CCC.Application.EndPoints.EndPoint<EndPointDeployment>ApplicationEndPoint
		{
			get { return applicationEndPoint; }
		}

		/// <summary>
		/// Start end point application
		/// </summary>
		/// <returns></returns>
		public EFS.RC.Common.AsyncProcess StartApplicationEndPoint(Microsoft.Rtc.Collaboration.ApplicationEndpointSettings applicationEndpointSettings)
		{
			// lock access
			lock (syncAccess)
			{
				// check if note already started
				if (null != applicationEndPoint)
				{
					throw new System.InvalidOperationException("Application End Point already started");
				}
				
				// instance
				applicationEndPoint = InstanceEndPointApplication(applicationEndpointSettings);

				// check
				EFS.Common.Verify.Reference(applicationEndPoint, "applicationEndPoint");

				// register for shut down
				applicationEndPoint.OnTerminated += OnApplicationEndPointTerminated;

				// start
				return applicationEndPoint.BeginStartup();
			}
		}

		/// <summary>
		/// Agent session terminated
		/// </summary>
		private void OnApplicationEndPointTerminated(EFS.RC.CCC.Application.EndPoints.EndPoint<EndPointDeployment> applicationEndPoint)
		{
			// lock access
			lock (syncAccess)
			{
				// check if this is our session
				if (null != this.applicationEndPoint && !this.applicationEndPoint.Equals(applicationEndPoint))
				{
					throw new System.InvalidOperationException("Different Application End Point received for terminated");
				}

				// un-register for shut down
				applicationEndPoint.OnTerminated -= OnApplicationEndPointTerminated;

				// remove end point
				this.applicationEndPoint = null;
			}
		}

		/// <summary>
		/// Create application instance
		/// </summary>
		/// <param name="applicationEndpointSettings"></param>
		/// <returns></returns>
		protected abstract EFS.RC.CCC.Application.EndPoints.EndPoint<EndPointDeployment>InstanceEndPointApplication(Microsoft.Rtc.Collaboration.ApplicationEndpointSettings applicationEndpointSettings);
	}
}
